1   /*
2    * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  /*
27   * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
28   * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
29   *
30   * The original version of this source code and documentation
31   * is copyrighted and owned by Taligent, Inc., a wholly-owned
32   * subsidiary of IBM. These materials are provided under terms
33   * of a License Agreement between Taligent and Sun. This technology
34   * is protected by multiple US and International patents.
35   *
36   * This notice and attribution to Taligent may not be removed.
37   * Taligent is a registered trademark of Taligent, Inc.
38   *
39   */
40  
41  package java.util;
42  
43  import sun.util.ResourceBundleEnumeration;
44  
45  /**
46   * <code>ListResourceBundle</code> is an abstract subclass of
47   * <code>ResourceBundle</code> that manages resources for a locale
48   * in a convenient and easy to use list. See <code>ResourceBundle</code> for
49   * more information about resource bundles in general.
50   *
51   * <P>
52   * Subclasses must override <code>getContents</code> and provide an array,
53   * where each item in the array is a pair of objects.
54   * The first element of each pair is the key, which must be a
55   * <code>String</code>, and the second element is the value associated with
56   * that key.
57   *
58   * <p>
59   * The following <a name="sample">example</a> shows two members of a resource
60   * bundle family with the base name "MyResources".
61   * "MyResources" is the default member of the bundle family, and
62   * "MyResources_fr" is the French member.
63   * These members are based on <code>ListResourceBundle</code>
64   * (a related <a href="PropertyResourceBundle.html#sample">example</a> shows
65   * how you can add a bundle to this family that's based on a properties file).
66   * The keys in this example are of the form "s1" etc. The actual
67   * keys are entirely up to your choice, so long as they are the same as
68   * the keys you use in your program to retrieve the objects from the bundle.
69   * Keys are case-sensitive.
70   * <blockquote>
71   * <pre>
72   *
73   * public class MyResources extends ListResourceBundle {
74   *     protected Object[][] getContents() {
75   *         return new Object[][] {
76   *         // LOCALIZE THIS
77   *             {"s1", "The disk \"{1}\" contains {0}."},  // MessageFormat pattern
78   *             {"s2", "1"},                               // location of {0} in pattern
79   *             {"s3", "My Disk"},                         // sample disk name
80   *             {"s4", "no files"},                        // first ChoiceFormat choice
81   *             {"s5", "one file"},                        // second ChoiceFormat choice
82   *             {"s6", "{0,number} files"},                // third ChoiceFormat choice
83   *             {"s7", "3 Mar 96"},                        // sample date
84   *             {"s8", new Dimension(1,5)}                 // real object, not just string
85   *         // END OF MATERIAL TO LOCALIZE
86   *         };
87   *     }
88   * }
89   *
90   * public class MyResources_fr extends ListResourceBundle {
91   *     protected Object[][] getContents() {
92   *         return new Object[][] = {
93   *         // LOCALIZE THIS
94   *             {"s1", "Le disque \"{1}\" {0}."},          // MessageFormat pattern
95   *             {"s2", "1"},                               // location of {0} in pattern
96   *             {"s3", "Mon disque"},                      // sample disk name
97   *             {"s4", "ne contient pas de fichiers"},     // first ChoiceFormat choice
98   *             {"s5", "contient un fichier"},             // second ChoiceFormat choice
99   *             {"s6", "contient {0,number} fichiers"},    // third ChoiceFormat choice
100  *             {"s7", "3 mars 1996"},                     // sample date
101  *             {"s8", new Dimension(1,3)}                 // real object, not just string
102  *         // END OF MATERIAL TO LOCALIZE
103  *         };
104  *     }
105  * }
106  * </pre>
107  * </blockquote>
108  * @see ResourceBundle
109  * @see PropertyResourceBundle
110  * @since JDK1.1
111  */
112 public abstract class ListResourceBundle extends ResourceBundle {
113     /**
114      * Sole constructor.  (For invocation by subclass constructors, typically
115      * implicit.)
116      */
117     public ListResourceBundle() {
118     }
119 
120     // Implements java.util.ResourceBundle.handleGetObject; inherits javadoc specification.
121     public final Object handleGetObject(String key) {
122         // lazily load the lookup hashtable.
123         if (lookup == null) {
124             loadLookup();
125         }
126         if (key == null) {
127             throw new NullPointerException();
128         }
129         return lookup.get(key); // this class ignores locales
130     }
131 
132     /**
133      * Returns an <code>Enumeration</code> of the keys contained in
134      * this <code>ResourceBundle</code> and its parent bundles.
135      *
136      * @return an <code>Enumeration</code> of the keys contained in
137      *         this <code>ResourceBundle</code> and its parent bundles.
138      * @see #keySet()
139      */
140     public Enumeration<String> getKeys() {
141         // lazily load the lookup hashtable.
142         if (lookup == null) {
143             loadLookup();
144         }
145 
146         ResourceBundle parent = this.parent;
147         return new ResourceBundleEnumeration(lookup.keySet(),
148                 (parent != null) ? parent.getKeys() : null);
149     }
150 
151     /**
152      * Returns a <code>Set</code> of the keys contained
153      * <em>only</em> in this <code>ResourceBundle</code>.
154      *
155      * @return a <code>Set</code> of the keys contained only in this
156      *         <code>ResourceBundle</code>
157      * @since 1.6
158      * @see #keySet()
159      */
160     protected Set<String> handleKeySet() {
161         if (lookup == null) {
162             loadLookup();
163         }
164         return lookup.keySet();
165     }
166 
167     /**
168      * Returns an array in which each item is a pair of objects in an
169      * <code>Object</code> array. The first element of each pair is
170      * the key, which must be a <code>String</code>, and the second
171      * element is the value associated with that key.  See the class
172      * description for details.
173      *
174      * @return an array of an <code>Object</code> array representing a
175      * key-value pair.
176      */
177     abstract protected Object[][] getContents();
178 
179     // ==================privates====================
180 
181     /**
182      * We lazily load the lookup hashtable.  This function does the
183      * loading.
184      */
185     private synchronized void loadLookup() {
186         if (lookup != null)
187             return;
188 
189         Object[][] contents = getContents();
190         HashMap<String,Object> temp = new HashMap<>(contents.length);
191         for (int i = 0; i < contents.length; ++i) {
192             // key must be non-null String, value must be non-null
193             String key = (String) contents[i][0];
194             Object value = contents[i][1];
195             if (key == null || value == null) {
196                 throw new NullPointerException();
197             }
198             temp.put(key, value);
199         }
200         lookup = temp;
201     }
202 
203     private Map<String,Object> lookup = null;
204 }